package com.tuzhi.filestore.controller;

import cn.hutool.core.io.FileUtil;
import com.tuzhi.base.web.helper.AjaxResultHelper;
import com.tuzhi.base.web.util.TZFileUtils;
import com.tuzhi.base.web.vo.AjaxResultVO;
import com.tuzhi.base.web.vo.Result;
import com.tuzhi.common.constants.ResultConstant;
import com.tuzhi.common.exception.BusinessException;
import com.tuzhi.filestore.config.FileStoreConfig;
import com.tuzhi.filestore.http.BillApiClient;
import com.tuzhi.filestore.http.FileStoreOtherApi;
import com.tuzhi.filestore.websocket.server.WebSocketHelp;
import com.tuzhi.filestore.websocket.vo.OrderStatusMsgVo;
import com.tuzhi.vo.bill.FileUpLogVo;
import com.tuzhi.vo.bill.FilesModelVo;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * 此接口全是替换BILL 上的转发，为实现只用一份代码 功能
 */
@RestController
@RequestMapping("/model")
@Slf4j
public class FileModelController {


    @Autowired
    BillApiClient billApiClient;

    @Autowired
    FileStoreConfig fileStoreConfig;
    @Resource
    FileStoreOtherApi fileStoreOtherApi;

    /**
     * 修改模型文件 状态
     *
     * @param mid    模型文件ID,上传文件返回给调用端的ID
     * @param status 状态字符串（ waiting, converting, converted, processing, processed, error, netError）
     * @return
     */
    @ApiIgnore
    @GetMapping(value = {"/updateStatus/{mid}/{status}"})
    public AjaxResultVO updateStatus(@PathVariable("mid") Long mid, @PathVariable("status") String status) {
        try {
            log.warn("修改模型文件状态,模型文件ID:{},状态：{}", mid, status);
            return billApiClient.updateStatus(mid, status);
        } catch (Exception ex) {
            AjaxResultVO ajaxResultVO = AjaxResultHelper.error();
            ajaxResultVO.setMsg(ExceptionUtils.getRootCauseMessage(ex));
            return ajaxResultVO;
        }

    }

    @ApiOperation(value = "获取模型信息")
    @GetMapping(value = "/{modelId}")
    public AjaxResultVO getModelFile(@PathVariable("modelId") Long modelId) {
        log.info("getModelFile:{}", modelId);
        AjaxResultVO ajaxResultVO = null;
        try {
            ajaxResultVO = billApiClient.getModelFile(modelId);
            log.info("call bill result:{}", ajaxResultVO);
            return ajaxResultVO;
        } catch (Exception ex) {
            ajaxResultVO = AjaxResultHelper.error();
            ajaxResultVO.setMsg("获取模型信息失败：" + ExceptionUtils.getRootCauseMessage(ex));
            return ajaxResultVO;
        }

    }


    /**
     * 文件下载
     *
     * @param modelId  id
     * @param request  请求
     * @param response 响应
     */
    @ApiOperation(value = "下载文件")
    @GetMapping(value = "/down/{type}/{modelId}")
    public void downFile(@PathVariable("modelId") Long modelId, @PathVariable("type") String fileType, HttpServletRequest request
            , HttpServletResponse response, @RequestHeader(required = false) String redirect) {
        OutputStream outputStream = null;
        InputStream inputStream = null;
        //log.info("downFile:modelId:{},fileType:{}", modelId, fileType);
        try {
            if (modelId == null) {
                throw new BusinessException("modelId 请求参数为空");
            }

//            log.info("result:{}", "getDownFilePath");
            Result<List<String>> result = billApiClient.getDownFilePath(fileType, modelId);
//            log.info("result:{}", result);
            if (result != null && result.getCode().equals("0")) {
                // String filePath = ajaxResultVO.getData().toString();
                List<String> paths = result.getData();
                if (paths == null || paths.isEmpty()) {
                    throw new BusinessException("获取路径失败");
                }

                String filePath = Paths.get(fileStoreConfig.getSavePath(), paths.toArray(new String[0])).toString();


                //String filePath = String.format("/%s/%s", fileStoreConfig.getSavePath(), ajaxResultVO.getData().toString());


                //String filePath = Paths.get(fileStoreConfig.getSavePath(),ajaxResultVO.getData().toString()).toString();
                //log.info("filePath:{}", filePath);
                boolean fileExist = FileUtil.exist(filePath);
                if (!fileExist) {
                    boolean isRedirect = fileStoreConfig.redirectDownFile(redirect);//是否可以跳转到其他服务器下载
                    if (isRedirect) {
                        //文件不存在，不是跳转过来的请求，则跳转到另一个服务器
                        log.info("根据文件类型,modelId={}，fileType={}，跳转下载", modelId, fileType);
                        inputStream = fileStoreOtherApi.downFileByFileType(modelId, fileType);
                        TZFileUtils.downFile(filePath, null, request, response, inputStream);
                    } else {
                        throw new BusinessException(String.format("文件不存在：%s", filePath));
                    }
                } else {
                    File file = new File(filePath);
                    String filename = FilenameUtils.getName(filePath);
                    inputStream = new FileInputStream(file);
                    response.setHeader("Content-Disposition", "attachment;filename=" + TZFileUtils.convertToFileName(request, filename));
                    // 获取输出流
                    outputStream = response.getOutputStream();
                    IOUtils.copy(inputStream, outputStream);
                }
            } else {
                throw new BusinessException(String.format("文件不存在：modelId: %s", modelId));
            }

        } catch (IOException e) {
            log.error("文件下载出错", e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                log.error("  文件下载，关闭资源出错", e);
            }
        }
    }


    @ApiOperation(value = "上传文件")
    @PostMapping("/upload")
    public AjaxResultVO upload(@RequestParam(name = "files", required = true) MultipartFile[] multipartFiles, @RequestParam(name = "keepname", required = true) String keepname) {
        //log.info("keepname:{}", keepname);
        //log.info("file:{}", multipartFiles.length);
        try {
            if (multipartFiles == null) {
                throw new BusinessException("文件不能为空");
            }
            if (StringUtils.isEmpty(keepname)) {
                throw new BusinessException("保存目录不能为空");
            }

            List<FileUpLogVo> fileUpLogVos = new ArrayList<>();
            for (MultipartFile file : multipartFiles) {
                String path = Paths.get(fileStoreConfig.getSavePath(), keepname).toString();
                TZFileUtils.uploadFile(file, path, false, null, null);
                fileUpLogVos.add(multipartFile2FileUpLogVo(file, keepname));
            }
            //TODO 调用保存上传日志接口
            return billApiClient.saveUpLogs(fileUpLogVos);
        } catch (Exception ex) {
            log.warn("上传异常，upload-{}-{}", keepname, ExceptionUtils.getRootCauseStackTrace(ex));
            ResultConstant.RC rc = new ResultConstant.RC("uploadFilessErr", ex.getMessage());
            AjaxResultVO ajax = AjaxResultHelper.build(rc);
            return ajax;
        }
    }

    private FileUpLogVo multipartFile2FileUpLogVo(MultipartFile multipartFile, String ncDir) {
        FileUpLogVo fileUpLogEntity = new FileUpLogVo();
        fileUpLogEntity.setFileName(multipartFile.getOriginalFilename());
        fileUpLogEntity.setOriginalFileName(multipartFile.getOriginalFilename());
        //fileUpLogEntity.setCreatedTime(new Date());
        fileUpLogEntity.setFileSize(multipartFile.getSize());
        fileUpLogEntity.setFtpDir(ncDir);
        fileUpLogEntity.setSource("ANALYSE");
        return fileUpLogEntity;
    }

    /**
     * 1.自动路线流程（技术中心从文档管理系统过来的报价模型）：
     * (1)后台接收到解释器完成：processed，我们将状态改成：sysAutoCheck，并发送WebSocket消息到自动路线程序
     * (2)假如通知WebSocket消息到自动路线程序的客户端为0，则直接更新状态为：processed，这样的话前端才可以看到这个单为可报价状态
     * (3)自动路线程序会通过WebSocket发送消息类型为：autoCheckResult 的消息过来，告诉识别结果，无论结果如何，后能把模型状态更新为：processed
     *
     * @param filesModelVo
     * @param id
     * @return
     */

    @ApiOperation(value = "更新模型")
    @PutMapping(value = {"/update/{modelId}"})
    public AjaxResultVO update(@RequestBody FilesModelVo filesModelVo, @PathVariable(value = "modelId", required = true) Long id) {
        try {
            log.info("更新模型信息：modelId-{}-{}", id, filesModelVo);
            if (filesModelVo == null) {
                return AjaxResultHelper.build(ResultConstant.ERR_PARAM_NULL);
            }
            String billHeaderSource = null;
            Result<Map> billHeaderMap = billApiClient.getBillOrderHeader(id);
            if (billHeaderMap != null && billHeaderMap.getData() != null) {
                Map billHeadMap = billHeaderMap.getData();
                String source = MapUtils.getString(billHeadMap, "source", "");
                if ("app001".equals(source) ||
                        "app-test".equals(source)) {
                    billHeaderSource = "app001";//技术中心文档管理系统过来的文档;
                    //获取FilesModelVo的状态，如果是processed，则改成，sysAutoCheck---系统自检中，让系统自动报价
                    if (filesModelVo.getData() != null) {
                        if ("processed".equals(filesModelVo.getData().getStatus())) {
                            log.info("将状态改成 sysAutoCheck");
                            filesModelVo.getData().setStatus("sysAutoCheck");
                        }
                    }
                }
            }
            log.info(" {} 更新模型 filesModelVo hyg  {}", id, filesModelVo);
            AjaxResultVO ajaxResultVO = billApiClient.update(filesModelVo, id);
           /* if ("app001".equals(billHeaderSource)) {
                //根据报价系统订单头表信息中的source，如果是来源为技术中心文档管理系统传过来的数据（source为app001）,则要调用websocket专用客户端面
                callWs4App(ajaxResultVO, filesModelVo, id);
            }*/
            callWs(ajaxResultVO, filesModelVo, id, billHeaderSource);
            return ajaxResultVO;
        } catch (Exception ex) {
            log.info("更新模型信息：modelId-{}异常", id);
            ResultConstant.RC rc = new ResultConstant.RC("异常", ExceptionUtils.getRootCauseMessage(ex));
            return AjaxResultHelper.build(rc);
        }
    }


    @ApiOperation(value = "前端直接调用的更新模型")
    @GetMapping(value = {"/updateModelStatus/{mid}/{status}"})
    public AjaxResultVO updateModelStatus(@PathVariable("mid") Long mid, @PathVariable("status") String status) {
        try {
            log.info("更新模型信息：modelId-{}-{}", mid, status);

            FilesModelVo filesModelVo = new FilesModelVo();
            FilesModelVo.ModelVo modelVo = filesModelVo.new ModelVo();
            filesModelVo.setData(modelVo);
            modelVo.setStatus(status);
            log.info(" {} 更新模型 filesModelVo {}", mid, filesModelVo);
            AjaxResultVO ajaxResultVO = billApiClient.update(filesModelVo, mid);
            return ajaxResultVO;
        } catch (Exception ex) {
            log.info("更新模型信息：modelId-{}异常", mid);
            ResultConstant.RC rc = new ResultConstant.RC("异常", ExceptionUtils.getRootCauseMessage(ex));
            return AjaxResultHelper.build(rc);
        }
    }


    @Async
    public void callWs(AjaxResultVO ajaxResultVO, FilesModelVo filesModelVo, Long mid, String billHeaderSource) {
        log.info("异步调用通知前端订单状态发生变化:{}", billHeaderSource);
        try {
            if (ajaxResultVO != null && ajaxResultVO.getCode().equals("0")) {
                OrderStatusMsgVo orderStatusMsgVo = new OrderStatusMsgVo();
                orderStatusMsgVo.setStatus(filesModelVo.getData().getStatus());
                orderStatusMsgVo.setModelId(mid);
                orderStatusMsgVo.setSource(billHeaderSource);
                Map<String, Integer> resultMap = WebSocketHelp.sendOrderStatus(orderStatusMsgVo);
                if ("sysAutoCheck".equals(orderStatusMsgVo.getStatus()) && MapUtils.getInteger(resultMap, "AutoCheckClient", 0) <= 0) {
                    //需要系统自动检查的订单联系不到”系统自动检查客户端“，直接更新为”processed"
                    billApiClient.updateStatus(mid, "processed");
                    filesModelVo.getData().setStatus("processed");
                    String msg = String.format("modelId=%s，组织=%s，自动路线没有在线的客户端。", mid, fileStoreConfig.getOrg());
                    log.info(msg);
                    billApiClient.sendWarmMail(mid, msg, msg);
                    callWs(ajaxResultVO, filesModelVo, mid, null);
                }
                log.info("异步调用通知前端订单状态发生变化 完成");
            }
        } catch (Exception ex) {
            log.error("收到更新订单订单，通知前端，异常：{}", ExceptionUtils.getStackTrace(ex));
        }
    }


    @ApiOperation(value = "获取模型信息")
    @GetMapping(value = "/testws/{modelId}")
    public AjaxResultVO testws(@PathVariable("modelId") Long modelId) {
        log.info("getModelFile:{}", modelId);
        OrderStatusMsgVo orderStatusMsgVo = new OrderStatusMsgVo();
        orderStatusMsgVo.setStatus("processing");
        orderStatusMsgVo.setModelId(modelId);
        try {
            WebSocketHelp.sendOrderStatus(orderStatusMsgVo);
        } catch (Exception e) {
//            throw new RuntimeException(e);
            log.error("ss", e);
            return AjaxResultHelper.error();
        }
        return AjaxResultHelper.success();
    }
}

